//
//  GLTexture.m
//  LMPhotoVideoSDK
//
//  Created by Aimar on 16/7/6.
//  Copyright © 2016年 魁钺会. All rights reserved.
//

#import "GLTexture.h"

static NSMutableDictionary*     sTextureCaches = nil;

@interface GLTexture () {
    GLubyte*         _imageData;
}

@property (nonatomic, strong)UIImage*       image;

@end

@implementation GLTexture

+ (GLTexture*)createTextureWithUIImage:(UIImage*)image {
    if (sTextureCaches == nil) {
        sTextureCaches = [NSMutableDictionary dictionaryWithCapacity:50];
    }
    
    GLTexture* texture = [sTextureCaches objectForKey:@(image.hash)];
    if (texture == nil) {
        texture = [[GLTexture alloc] initWithUIImage:image];
        [sTextureCaches setObject:texture forKey:@(image.hash)];
    }
    
    return texture;
}

- (id)initWithUIImage:(UIImage*)image {
    self = [super init];
    if (self) {
        _imageData = NULL;
        
        self.image = image;
        self.modeS = GL_CLAMP_TO_EDGE;
        self.modeT = GL_CLAMP_TO_EDGE;
    }
    
    return self;
}

- (void)releaseImageData {
    if (_imageData != NULL) {
        free(_imageData);
        _imageData = NULL;
    }
}

- (void)releaseTexture {
    if (self.image) {
        [sTextureCaches removeObjectForKey:@(self.image.hash)];
        self.image = nil;
    }
    [self releaseImageData];
    glDeleteTextures(1, &_textureId);
    _textureId = 0;
}

- (void)updateSubImage:(UIImage*)subImage {
    if (self.textureId == 0) {
        [self genTexture];
    } else {
        glBindTexture(GL_TEXTURE_2D, self.textureId);
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, self.size.width, self.size.height, GL_RGBA, GL_UNSIGNED_BYTE, _imageData);
    }
}

- (BOOL)bind {
    if (self.textureId == 0) {
        return [self genTexture];
    }
    
    glBindTexture(GL_TEXTURE_2D, _textureId);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, self.modeS);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, self.modeT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
    return YES;
}

#pragma mark Internal CreatePixelData
- (void)createImageData {
    [self releaseImageData];
    
    CGImageRef cgImage = self.image.CGImage;
    if (cgImage) {
        _size.width = CGImageGetWidth(cgImage);
        _size.height = CGImageGetHeight(cgImage);
        CFDataRef dataRef = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
        _imageData = (GLubyte*)CFDataGetBytePtr(dataRef);
    }
}

#pragma mark Internal GenTexture
- (BOOL)genTexture {
    [self createImageData];
    
//    if (_imageData == NULL) {
//        return NO;
//    }
    
    glGenTextures(1, &_textureId);
    glBindTexture(GL_TEXTURE_2D, _textureId);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, self.modeS);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, self.modeT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.size.width, self.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, _imageData);
    glGenerateMipmap(GL_TEXTURE_2D);
    [self releaseImageData];
    
    return YES;
}

@end
